///<copyright>
/// Microsoft XNA Community Game Platform
/// Copyright (C) Microsoft Corporation. All rights reserved.
///</copyright>
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Ferpect.ComponentModel.Sprites
{
    /// <summary>
    /// particles are the little bits that will make up an effect. each effect will
    /// be comprised of many of these particles. They have basic physical properties,
    /// such as position, velocity, acceleration, and rotation. They'll be drawn as
    /// sprites, all layered on top of one another, and will be very pretty.
    /// </summary>
    public struct Particle
    {
        public static Random Random = new Random();

        // Position, Velocity, and Acceleration represent exactly what their names
        // indicate. They are public fields rather than properties so that users
        // can directly access their .X and .Y properties.
        public Vector2 Position;
        public Vector2 Velocity;
        public Vector2 Acceleration;

        // how long this particle will "live"
        public float Lifetime;

        // how long it has been since initialize was called
        public float TimeSinceStart;

        // the scale of this particle
        public float Scale;

        // its rotation, in radians
        public float Rotation;

        // how fast does it rotate?
        public float RotationSpeed;

        // is this particle still alive? once TimeSinceStart becomes greater than
        // Lifetime, the particle should no longer be drawn or updated.
        public bool Active
        {
            get { return TimeSinceStart < Lifetime; }
        }
        
        // initialize is called by ParticleSystem to set up the particle, and prepares
        // the particle for use.
        public void Initialize(Vector2 position, Vector2 velocity, Vector2 acceleration, float lifetime, float scale, float rotationSpeed)
        {
            // set the values to the requested values
            this.Position = position;
            this.Velocity = velocity;
            this.Acceleration = acceleration;
            this.Lifetime = lifetime;
            this.Scale = scale;
            this.RotationSpeed = rotationSpeed;
            
            // reset TimeSinceStart - we have to do this because particles will be
            // reused.
            this.TimeSinceStart = 0.0f;

            // set rotation to some random value between 0 and 360 degrees.
            this.Rotation = (float)Particle.Random.NextDouble() * MathHelper.TwoPi;
        }

        // update is called by the ParticleSystem on every frame. This is where the
        // particle's position and that kind of thing get updated.
        public void Update(float dt)
        {
            Velocity += Acceleration * dt;
            Position += Velocity * dt;
            Rotation += RotationSpeed * dt;
            TimeSinceStart += dt;
        }

        public void Draw(SpriteBatch spriteBatch, Texture2D texture, ref Color color, ref Vector2 origin)
        {
            float normalizedLifetime = this.TimeSinceStart / this.Lifetime;

            // we want particles to fade in and fade out, so we'll calculate alpha
            // to be (normalizedLifetime) * (1-normalizedLifetime). this way, when
            // normalizedLifetime is 0 or 1, alpha is 0. the maximum value is at
            // normalizedLifetime = .5, and is
            // (normalizedLifetime) * (1-normalizedLifetime)
            // (.5)                 * (1-.5)
            // .25
            // since we want the maximum alpha to be 1, not .25, we'll scale the 
            // entire equation by 4.
            float alpha = 4 * normalizedLifetime * (1 - normalizedLifetime);
            Color newColor = Color.Multiply(color, alpha);

            // make particles grow as they age. they'll start at 75% of their size,
            // and increase to 100% once they're finished.
            float scale = this.Scale * (.75f + .25f * normalizedLifetime);

            spriteBatch.Draw(texture, this.Position, null, newColor, this.Rotation, origin, scale, SpriteEffects.None, 0.0f);
        }
    }
}
